# Table_A15.R

# Part of the replication archive for 
#
#   Bullock, John G. 2020. "Education and Attitudes toward Redistribution in
#   the United States." British Journal of Political Science 50.


# This file produces Table A15 in the appendix to the article: "Results from a
# minimal specification."


library(Bullock, lib.loc = c(.libPaths(), 'packageLibrary'))  # for qw()
library(ivpack)   # for cluster.robust.se
source("IV_setup.R")
filenameStem <- 'float_output/Table_A15'



##############################################################################
# 2SLS ESTIMATES FROM THE MINIMAL SPECIFICATION
##############################################################################
# CREATE THE MINIMAL MODEL
IVModelEnvMin <- IVModelsEnv
rm(list = ls(pat = '.*[2-9]', envir = IVModelEnvMin), envir = IVModelEnvMin)
IVModelEnvMin$eqwlth.mod1 <- update(
  IVModelEnvMin$eqwlth.mod1,
  . ~ educ + yearYoungNorm + stateYoung | CA.fac + yearYoungNorm + stateYoung)
attributes(IVModelEnvMin$eqwlth.mod1)$modNum <- 1


# CREATE DATA FRAMES
# We want to use the same data frame for the 2SLS estimates, the first stage,
# and the reduced form.
GSS.df$educ1      <- GSS.df$educ2 <- GSS.df$educ5 <- GSS.df$educ6 <- GSS.df$educ
ANES.df$educ3     <- ANES.df$educ4 <- ANES.df$educ
GSS.df.eqwlth     <- GSS.df [!is.na(GSS.df$eqwlth)           & !is.na(GSS.df$educ), ]
GSS.df.goveqinc   <- GSS.df [!is.na(GSS.df$goveqinc)         & !is.na(GSS.df$educ), ]
ANES.df.guarantee <- ANES.df[!is.na(ANES.df$guarantee.7pt)   & !is.na(ANES.df$educ), ]
ANES.df.health    <- ANES.df[!is.na(ANES.df$govt.health.7pt) & !is.na(ANES.df$educ), ]
GSS.df.helppoor   <- GSS.df [!is.na(GSS.df$helppoor)         & !is.na(GSS.df$educ), ]
GSS.df.welfare    <- GSS.df [!is.na(GSS.df$welfare)          & !is.na(GSS.df$educ), ]
dfNames  <- qw(
  "GSS.df.eqwlth  GSS.df.goveqinc ANES.df.guarantee
   ANES.df.health GSS.df.helppoor GSS.df.welfare") 
varNames     <- qw('eqwlth goveqinc guarantee.7pt govt.health.7pt helppoor welfare')
varNamesEduc <- paste0('educ', 1:length(dfNames))


# ESTIMATE THE MODELS WITH 2SLS
IVModelObjectsEnv.min <- estimateModels(
  varNames     = varNames, 
  modelEnvir   = IVModelEnvMin, 
  dfNames      = dfNames,
  objectSuffix = '.IV') 
mainEstsEduc.min <- estTable(
  varNames    = varNames, 
  treatment   = 'educ', 
  objectEnvir = IVModelObjectsEnv.min,
  clusterSEs  = TRUE)

# FIRST-STAGE F STATISTICS
Fstats <- eapply(
    env = IVModelObjectsEnv.min, 
    FUN = function (x) summary(x, diagnostics = TRUE)$diagnostics['Weak instruments', 'statistic']) %>%
.[sort(names(.))]

# REDUCED FORM
RF_modelsMin <- eapply(IVModelEnvMin, getReducedForm)  
RF_modelsMin <- addModNumAttribute(RF_modelsMin) 
RF_modelsMin <- list2env(RF_modelsMin)
RF_modelObjectsEnv.min <- estimateModels(
  varNames     = varNames, 
  modelEnvir   = RF_modelsMin,  
  dfNames      = dfNames,
  estFun       = lm,
  objectSuffix = '.lm') 

# R TABLE
minSpecEsts <- matrix(NA, length(varNames), 4)
rownames(minSpecEsts) <- varNames
colnames(minSpecEsts) <- qw("2SLS.est 2SLS.SE F N")
minSpecEsts[, qw("2SLS.est 2SLS.SE")] <- matrix(mainEstsEduc.min, 6, 2, byrow = TRUE)
minSpecEsts[, 'F'] <- as.numeric(Fstats)
minSpecEsts[, 'N'] <- unlist(eapply(IVModelObjectsEnv.min, nobs)[paste0(varNames, '.IV1')])



##############################################################################
# CREATE LATEX TABLE
##############################################################################
rownamesMinSpec <- c(
  'redistribution to the poor (1)',
  'redistribution to the poor (2)',
  'guaranteed standard of living',
  'health care',
  'help the poor',
  'welfare')
colnamesMinSpec <- c('2SLS', '', 'F', 'N')
minSpecCaption  <- "\\textit{Results from a minimal specification.} This table presents estimates from a minimal model in which attitudes are regressed only on years of education, state fixed effects, and a linear trend for the year in which respondents were born. As in the main analyses, compulsory attendance instruments for years of education."
minSpecTable    <- latexTable(
  mat                = minSpecEsts,
  SETable            = FALSE,
  decimalPlaces      = 3,
  rowNames           = rownamesMinSpec,
  colNames           = colnamesMinSpec,
  colNameExpand      = TRUE,
  spacerColumns      = c(0, 2, 3),
  spacerColumnsWidth = ".6em",
  tabcolsep          = "4.75pt",
  headerFooter       = TRUE,
  footerRows         = NULL,
  caption            = minSpecCaption, 
  captionMargins     = qw(".75in .70in"),
  commandName        = 'TabMinSpec',
  callCommand        = FALSE)

# TWEAK THE LATEX CODE
# First change is for standard errors in the second column.
minSpecTableRowToChange               <- grep('N{0}{3}', minSpecTable, fixed = TRUE)[2]
minSpecTable[minSpecTableRowToChange] <- sub(
  pattern     = '\\hspace*{0em}', 
  replacement = '\\fontsize{10.3bp}{10.3bp}\\selectfont', 
  x           = minSpecTable[minSpecTableRowToChange],
  fixed       = TRUE)

minSpecTableRowToChange               <- grep('N{5}{3}', minSpecTable, fixed = TRUE)
minSpecTable[minSpecTableRowToChange] <- sub(
  pattern     = 'N{5}{3}', 
  replacement = 'N{5}{0}', 
  x           = minSpecTable[minSpecTableRowToChange],
  fixed       = TRUE)

minSpecTableRowToChange               <- grep('{3}{c}{2SLS}', minSpecTable, fixed = TRUE)
minSpecTable[minSpecTableRowToChange] <- sub(
  pattern     = '{3}{c}{2SLS}', 
  replacement = '{2}{c}{2SLS}', 
  x           = minSpecTable[minSpecTableRowToChange],
  fixed       = TRUE)

minSpecTableRowToChange <- grep('(lr){3-5}', minSpecTable, fixed = TRUE)
minSpecTable[minSpecTableRowToChange] <- sub(
  pattern     = '(lr){3-5}', 
  replacement = '{3-4}', 
  x           = minSpecTable[minSpecTableRowToChange], 
  fixed       = TRUE)

minSpecTableRowToChange <- grep('(lr){7-7}', minSpecTable, fixed = TRUE)
minSpecTable[minSpecTableRowToChange] <- sub(
  pattern     = '(lr){7-7}', 
  replacement = '{6-6}', 
  x           = minSpecTable[minSpecTableRowToChange], 
  fixed       = TRUE)

minSpecTableRowToChange <- grep('(lr){9-9}', minSpecTable, fixed = TRUE)
minSpecTable[minSpecTableRowToChange] <- sub(
  pattern     = '(lr){9-9}', 
  replacement = '{8-8}',
  x           = minSpecTable[minSpecTableRowToChange], 
  fixed       = TRUE)

minSpecTableRowToChange <- grep('captionsetup{margin', minSpecTable, fixed = TRUE)
minSpecTable[minSpecTableRowToChange] <- sub(
  pattern     = 'captionsetup{margin', 
  replacement = 'captionsetup{aboveskip=\\baselineskip, margin',
  x           = minSpecTable[minSpecTableRowToChange], 
  fixed       = TRUE)

# WRITE THE TABLE TO A FILE
latexTablePDF(
  latexCommands      = list(minSpecTable), 
  firstPageEmpty     = FALSE,
  wrapper            = FALSE,  # FALSE if inserting LaTeX tables into appendix of my paper
  outputFilenameStem = filenameStem,       
  overwriteExisting  = TRUE,
  keepPDFFile        = FALSE,
  keepTexFile        = TRUE,
  openPDFOnExit      = FALSE)



##############################################################################
# AUXILIARY RESULTS
##############################################################################
if (interactive()) {
  RF_clusters <- lapply(RF_modelObjectsEnv.min, getClusters)
  vcovs.clustered <- mapply(
    FUN      = cluster.vcov,
    model    = as.list(RF_modelObjectsEnv.min),
    cluster  = RF_clusters,
    SIMPLIFY = FALSE)
  coefsAndSEs <- mapply(
    FUN   = coeftest,
    x     = as.list(RF_modelObjectsEnv.min),
    vcov. = vcovs.clustered,
    SIMPLIFY = FALSE)
  lapply(coefsAndSEs, function (x) x[2:3, c("Estimate", "Std. Error")])[sort(names(coefsAndSEs))]
}